home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 1
/
Nebula One.iso
/
Mail
/
pine3.92
/
pico
/
attach.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-16
|
25KB
|
1,023 lines
#if !defined(lint) && !defined(DOS)
static char rcsid[] = "$Id: attach.c,v 4.33 1996/03/16 21:50:43 mikes Exp $";
#endif
/*
* Program: Routines to support attachments in the Pine composer
*
*
* Michael Seibel
* Networks and Distributed Computing
* Computing and Communications
* University of Washington
* Administration Builiding, AG-44
* Seattle, Washington, 98195, USA
* Internet: mikes@cac.washington.edu
*
* Please address all bugs and comments to "pine-bugs@cac.washington.edu"
*
*
* Pine and Pico are registered trademarks of the University of Washington.
* No commercial use of these trademarks may be made without prior written
* permission of the University of Washington.
*
* Pine, Pico, and Pilot software and its included text are Copyright
* 1989-1996 by the University of Washington.
*
* The full text of our legal notices is contained in the file called
* CPYRIGHT, included with this distribution.
*
*/
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include "osdep.h"
#include "pico.h"
#include "estruct.h"
#include "edef.h"
#include "efunc.h"
#ifdef ATTACHMENTS
#ifdef ANSI
int ParseAttach(struct hdr_line **,int *,char *,char *,char *,int *);
PATMT *NewAttach(char *, long, char *);
void ZotAttach(struct pico_atmt *);
int sinserts(char *, int, char *, int);
int AttachUpload(char *, char *);
int AttachCancel(char *);
#else
int ParseAttach();
PATMT *NewAttach();
void ZotAttach();
int sinserts();
int AttachUpload();
int AttachCancel();
#endif
/*
* max number of attachments
*/
#define MAXATCH 64
#define HIBIT_WARN "Only ASCII characters allowed in attachment comments"
/*
* AskAttach - ask for attachment fields and build resulting structure
* return pointer to that struct if OK, NULL otherwise
*/
AskAttach(fn, sz, cmnt)
char *fn, *sz, *cmnt;
{
int i, status, upload = 0;
long l = 0;
char bfn[NFILEN];
i = 2;
fn[0] = '\0';
sz[0] = '\0';
cmnt[0] = '\0';
while(i){
if(i == 2){
EXTRAKEYS menu_attach[3];
int n;
menu_attach[n = 0].name = "^T";
menu_attach[n].label = "To Files";
menu_attach[n].key = (CTRL|'T');
#if !defined(DOS) && !defined(MAC)
if(Pmaster && Pmaster->upload){
/*
* The Plan: ^R prompts for uploaded file's name which
* is passed to the defined upload command when the user
* hits Return to confirm the name.
* NOTE: this is different than upload into message
* text in which case the uploaded name isn't useful so
* a temp file is ok (be sure to fix the file mode).
*/
menu_attach[++n].name = "^Y";
menu_attach[n].key = (CTRL|'Y');
menu_attach[n].label = upload ? "Read File" : "RcvUpload";
}
#endif
menu_attach[++n].name = NULL;
KS_OSDATASET(&menu_attach[0], KS_NONE);
status = mlreply(upload ? "Name to give uploaded attachment: "
: "File to attach: ",
fn, NLINE, QNORML, menu_attach);
}
else
status = mlreply("Attachment comment: ", cmnt, NLINE, QNORML, NULL);
switch(status){
case HELPCH:
emlwrite("No Attachment %s help yet!",
(i == 2) ? "file" : "comment");
/* remove break and sleep when help text done to force redraw */
sleep(3);
break;
case (CTRL|'T'):
if(i != 2){
(*term.t_beep)();
break;
}
*bfn = '\0';
if(*fn == '\0' || !isdir(fn, NULL))
strcpy(fn, gmode&MDCURDIR ? "."
: (gmode&MDTREE) ? opertree
: gethomedir(NULL));
if(FileBrowse(fn, bfn, sz, FB_READ) == 1){
strcat(fn, S_FILESEP);
strcat(fn, bfn);
if(upload && !AttachUpload(fn, sz)){
i = 2; /* keep prompting for file */
sleep(3); /* problem, show error! */
}
else
i--; /* go prompt for comment */
}
else
*fn = '\0';
/* fall thru to clean up the screen */
case (CTRL|'L'):
refresh(FALSE, 1);
update();
continue;
#if !defined(DOS) && !defined(MAC)
case (CTRL|'Y'): /* upload? */
if(i == 2)
upload ^= 1; /* flip mode */
else
(*term.t_beep)();
break;
#endif
case ABORT:
return(AttachCancel((upload && i == 1) ? fn : NULL));
case TRUE: /* some comment */
case FALSE: /* No comment */
if(i-- == 2){
if(upload){
fixpath(fn, NLINE); /* names relative to ~ */
status = AttachUpload(fn, sz);
refresh(FALSE, 1);
update();
if(!status){
i = 2; /* keep prompting for file */
sleep(3); /* problem, show error! */
}
}
else if(fn[0]){
if(gmode&MDTREE)
compresspath(opertree, fn, NLINE);
fixpath(fn, NLINE); /* names relative to ~ */
if((gmode&MDTREE) && !in_oper_tree(fn)){
emlwrite(
"\007Restricted mode allows attachments from %s only",
(gmode&MDSCUR) ? "home directory" : opertree);
return(0);
}
if((status=fexist(fn, "r", &l)) != FIOSUC){
fioperr(status, fn); /* file DOESN'T exist! */
return(0);
}
strcpy(sz, prettysz(l));
}
else
return(AttachCancel((upload && i == 1) ? fn : NULL));
}
else{
mlerase();
return(1); /* mission accomplished! */
}
break;
default:
break;
}
}
}
/*
* AttachUpload - Use call back to run the external upload command.
*/
int
AttachUpload(fn, sz)
char *fn, *sz;
{
long l;
if(gmode&MDSCUR){
emlwrite("\007Restricted mode disallows uploaded command", NULL);
return(0);
}
if(Pmaster && Pmaster->upload && (*Pmaster->upload)(fn, &l)){
strcpy(sz, prettysz(l));
return(1);
}
return(0);
}
/*
* AttachCancel -
*/
int
AttachCancel(fn)
char *fn;
{
emlwrite("Attach cancelled", NULL);
if(fn && fn[0])
unlink(fn); /* blast uploaded file */
return(0);
}
extern struct headerentry *headents;
/*
* SyncAttach - given a pointer to a linked list of attachment structures,
* return with that structure sync'd with what's displayed.
* delete any attachments in list of structs that's not on
* the display, and add any that aren't in list but on display.
*/
SyncAttach()
{
int offset = 0, /* the offset to begin */
rv = 0,
ki = 0, /* number of known attmnts */
bi = 0, /* build array index */
na, /* old number of attachmnt */
status, i, j, n;
char file[NLINE], /* buffers to hold it all */
size[32],
comment[1024];
struct hdr_line *lp; /* current line in header */
struct headerentry *entry;
PATMT *tp, *knwn[MAXATCH], *bld[MAXATCH];
for(entry = headents; entry->name != NULL; entry++) {
if(entry->is_attach)
break;
}
if(Pmaster == NULL)
return(-1);
for(i=0;i<MAXATCH;i++) /* bug - ever pop this? */
knwn[i] = bld[i] = NULL; /* zero out table */
tp = Pmaster->attachments;
while(tp != NULL){ /* fill table of */
knwn[ki++] = tp; /* known attachments */
tp = tp->next;
}
n = 0;
lp = entry->hd_text;
while(lp != NULL){
na = ++n;
if(status = ParseAttach(&lp, &offset, file, size, comment, &na))
rv = (rv < 0) ? rv : status ; /* remember worst case */
if(*file == '\0'){
if(n != na && na > 0 && na <= ki && (knwn[na-1]->flags & A_FLIT)){
bld[bi++] = knwn[na-1];
knwn[na-1] = NULL;
}
continue;
}
if((gmode&MDTREE) && !in_oper_tree(file))
/* no attachments outsize ~ in secure mode! */
continue;
tp = NULL;
for(i = 0; i < ki; i++){ /* already know about it? */
/*
* this is kind of gruesome. what we want to do is keep track
* of literal attachment entries because they may not be
* actual files we can access or that the user can readily
* access.
*/
if(knwn[i]
&& ((!(knwn[i]->flags&A_FLIT)
&& !strcmp(file, knwn[i]->filename))
|| ((knwn[i]->flags&A_FLIT) && i+1 == na))){
tp = knwn[i];
knwn[i] = NULL; /* forget we know about it */
if(status == -1) /* ignore garbage! */
break;
if((tp->flags&A_FLIT) && strcmp(file, tp->filename)){
rv = 1;
if((j=strlen(file)) > strlen(tp->filename)){
if((tp->filename = (char *)realloc(tp->filename,
sizeof(char)*(j+1))) == NULL){
emlwrite("\007Can't realloc filename space",NULL);
return(-1);
}
}
strcpy(tp->filename, file);
}
else if(tp->size && strcmp(tp->size, size)){
rv = 1;
if((j=strlen(size)) > strlen(tp->size)){
if((tp->size=(char *)realloc(tp->size,
sizeof(char)*(j+1))) == NULL){
emlwrite("\007Can't realloc space for size", NULL);
return(-1);
}
}
strcpy(tp->size, size);
}
if(strcmp(tp->description, comment)){ /* new comment */
rv = 1;
if((j=strlen(comment)) > strlen(tp->description)){
if((tp->description=(char *)realloc(tp->description,
sizeof(char)*(j+1))) == NULL){
emlwrite("\007Can't realloc description", NULL);
return(-1);
}
}
strcpy(tp->description, comment);
}
break;
}
}
if(tp){
bld[bi++] = tp;
}
else{
if(file[0] != '['){
if((tp = NewAttach(file, atol(size), comment)) == NULL)
return(-1);
bld[bi++] = tp;
}
else break;
}
if(status < 0)
tp->flags |= A_ERR; /* turn ON error bit */
else
tp->flags &= ~(A_ERR); /* turn OFF error bit */
}
for(i=0; i < bi; i++) /* link together newly built list */
bld[i]->next = bld[i+1];
Pmaster->attachments = bld[0];
for(i = 0; i < ki; i++){ /* kill old/unused references */
if(knwn[i]){
ZotAttach(knwn[i]);
free((char *) knwn[i]);
}
}
return(rv);
}
/*
* ParseAttach - given a header line and an offset into it, return with
* the three given fields filled in. Assumes the size of
* the buffers passed is large enough to hold what's there.
* Always updates header fields that have changed or are
* fixed. An error advances offset to next attachment.
*
* returns: 1 if a field changed
* 0 nothing changed
* -1 on error
*/
ParseAttach(lp, off, fn, sz, cmnt, no)
struct hdr_line **lp; /* current header line */
int *off; /* offset into that line */
char *fn, *sz, *cmnt; /* places to return fields */
int *no; /* attachment number */
{
int j, status, /* various return codes */
rv = 0, /* return value */
orig_offset,
lbln = 0, /* label'd attachment */
hibit = 0;
long l; /* attachment length */
char tmp[1024],
c,
c_lookahead,
*p,
*lblsz = NULL, /* label'd attchmnt's size */
number[8];
register struct hdr_line *lprev;
enum { /* parse levels */
LWS, /* leading white space */
NUMB, /* attachment number */
WSN, /* white space after number */
TAG, /* attachments tag (fname) */
WST, /* white space after tag */
SIZE, /* attachments size */
SWS, /* white space after size */
CMMNT, /* attachment comment */
TG} level; /* trailing garbage */
*fn = *sz = *cmnt = '\0'; /* initialize return strings */
p = tmp;
orig_offset = *off;
level = LWS; /* start at beginning */
while(*lp != NULL){
if((c=(*lp)->text[*off]) == '\0'){ /* end of display line */
int lwsp = 0;
while(isspace((*lp)->text[lwsp]))
lwsp++;
if(lwsp){ /* blat leading whitespace */
*off -= lwsp;
for(j = 0; (*lp)->text[j] = (*lp)->text[j+lwsp]; j++)
;
}
while(*off && isspace((*lp)->text[*off - 1]))
(*lp)->text[--(*off)] = '\0'; /* blat trailing whitespace */
lprev = *lp;
if((*lp = (*lp)->next) != NULL)
c = (*lp)->text[*off = 0]; /* reset offset */
}
if(c != '\0')
c_lookahead = (*lp)->text[*off + 1];
switch(level){
case LWS: /* skip leading white space */
if(isspace(c) || c == '\0'){
break;
} else if(c == ','){
c = (*lp)->text[*off] = ' '; /* rub out stray comma */
break;
}
else if(!isdigit(c)){ /* add a number */
sprintf(number, "%d. ", *no);
*no = 0; /* no previous number! */
sinserts((*lp == NULL) ? &lprev->text[*off]
: &(*lp)->text[*off],
0, number, j=strlen(number));
*off += j - 1;
rv = 1;
level = TAG; /* interpret the name */
break;
}
level = NUMB;
case NUMB: /* attachment number */
if(c == '\0' || c == ','){ /* got to end, no number yet */
*p = '\0';
sprintf(number, "%d. ", *no);
*no = 0; /* no previous number! */
if(c == '\0')
*lp = lprev; /* go back and look at prev */
c = (*lp)->text[*off = orig_offset]; /* reset offset */
sinserts((*lp == NULL) ? &lprev->text[*off]
: &(*lp)->text[*off],
0, number, j=strlen(number));
*off += j - 1;
rv = 1;
p = tmp;
level = WSN; /* what's next... */
break;
}
else if(c == '.' /* finished grabbing number */
&& isspace(c_lookahead)){ /* if not space is not number */
/*
* replace number if it's not right
*/
*p = '\0';
sprintf(number, "%d", *no); /* record the current... */
*no = atoi(tmp); /* and the old place in list */
if(strcmp(number, tmp)){
if(p-tmp > *off){ /* where to begin replacemnt */
j = (p-tmp) - *off;
sinserts((*lp)->text, *off, "", 0);
sinserts(&lprev->text[strlen(lprev->text)-j], j,
number, strlen(number));
*off = 0;
}
else{
j = (*off) - (p-tmp);
sinserts((*lp == NULL) ? &lprev->text[j]
: &(*lp)->text[j],
p-tmp , number, strlen(number));
*off += strlen(number) - (p-tmp);
}
rv = 1;
}
p = tmp;
level = WSN; /* what's next... */
}
else if(c < '0' || c > '9'){ /* Must be part of tag */
sprintf(number, "%d. ", *no);
sinserts((*lp == NULL) ? &lprev->text[(*off) - (p - tmp)]
: &(*lp)->text[(*off) - (p - tmp)],
0, number, j=strlen(number));
*off += j;
level = TAG; /* interpret the name */
goto process_tag; /* in case already past end of tag */
}
else
*p++ = c;
break;
case WSN: /* blast whitespace */
if(isspace(c) || c == '\0'){
break;
}
else if(c == '['){ /* labeled attachment */
lbln++;
}
else if(c == ',' || c == ' '){
emlwrite("\007Attchmnt: '%c' not allowed in file name",
(void *)(int)c);
rv = -1;
level = TG; /* eat rest of garbage */
break;
}
level = TAG;
case TAG: /* get and check filename */
/* or labeled attachment */
process_tag: /* enclosed in [] */
if(c == '\0' || (!lbln && (isspace(c) || strchr(",(\"", c)))
|| (lbln && c == ']')){
if(p != tmp){
*p = '\0'; /* got something */
strcpy(fn, tmp); /* store file name */
if(!lbln){ /* normal file attachment */
if(gmode&MDTREE)
compresspath(opertree, fn, NLINE);
fixpath(fn, NLINE);
if((status=fexist(fn, "r", &l)) != FIOSUC){
fioperr(status, fn);
rv = -1;
level = TG; /* munch rest of garbage */
break;
}
if((gmode&MDTREE) && !in_oper_tree(fn)){
emlwrite("\007Attachments allowed only from %s",
(gmode&MDSCUR) ? "home directory" : opertree);
rv = -1;
level = TG;
break;
}
if(strcmp(fn, tmp)){ /* fn changed: display it */
if(*off >= p - tmp){ /* room for it? */
sinserts((*lp == NULL)?
&lprev->text[(*off)-(p-tmp)] :
&(*lp)->text[(*off)-(p-tmp)],
p-tmp, fn, j=strlen(fn));
*off += j - (p - tmp); /* advance offset */
rv = 1;
}
else{
emlwrite("\007Attchmnt: Problem displaying real file path", NULL);
}
}
}
else{ /* labelled attachment! */
/*
* should explain about labelled attachments:
* these are attachments that came into the composer
* with meaningless file names (up to caller of
* composer to decide), for example, attachments
* being forwarded from another message. here, we
* just make sure the size stays what was passed
* to us. The user is SOL if they change the label
* since, as it is now, after changed, it will
* just get dropped from the list of what gets
* passed back to the caller.
*/
PATMT *tp;
if(c != ']'){ /* legit label? */
emlwrite("\007Attchmnt: Expected ']' after \"%s\"",
fn);
rv = -1;
level = TG;
break;
}
strcat(fn, "]");
/*
* This is kind of cheating since otherwise
* ParseAttach doesn't know about the attachment
* struct. OK if filename's not found as it will
* get taken care of later...
*/
tp = Pmaster->attachments; /* caller check Pmaster! */
j = 0;
while(tp != NULL){
if(++j == *no){
lblsz = tp->size;
break;
}
tp = tp->next;
}
if(tp == NULL){
emlwrite("\007Attchmnt: Unknown reference: %s",fn);
lblsz = "XXX";
}
}
p = tmp; /* reset p in tmp */
level = WST;
}
if(!lbln && c == '(') /* no space 'tween file, size*/
level = SIZE;
else if(c == '\0' || (!lbln && (c == ',' || c == '\"'))){
strcpy(sz, (lblsz) ? lblsz : prettysz(l));
sprintf(tmp, " (%s) %s", sz, (c == '\"') ? "" : "\"\"");
sinserts((*lp == NULL) ? &lprev->text[*off]
: &(*lp)->text[*off],
0, tmp, j = strlen(tmp));
*off += j;
rv = 1;
level = (c == '\"') ? CMMNT : TG;/* cmnt or eat trash */
}
}
else if(!lbln && (c == ',' || c == ' ' || c == '[' || c == ']')){
emlwrite("\007Attchmnt: '%c' not allowed in file name",
(void *)(int)c);
rv = -1; /* bad char in file name */
level = TG; /* gobble garbage */
}
else
*p++ = c; /* add char to name */
break;
case WST: /* skip white space */
if(!isspace(c)){
/*
* whole attachment, comment or done!
*/
if(c == ',' || c == '\0' || c == '\"'){
strcpy(sz, (lblsz) ? lblsz : prettysz(l));
sprintf(tmp, " (%s) %s", sz,
(c == '\"') ? "" : "\"\"");
sinserts((*lp == NULL) ? &lprev->text[*off]
: &(*lp)->text[*off],
0, tmp, j = strlen(tmp));
*off += j;
rv = 1;
level = (c == '\"') ? CMMNT : TG;
lbln = 0; /* reset flag */
}
else if(c == '('){ /* get the size */
level = SIZE;
}
else{
emlwrite("\007Attchmnt: Expected '(' or '\"' after %s",fn);
rv = -1; /* bag it all */
level = TG;
}
}
break;
case SIZE: /* check size */
if(c == ')'){ /* finished grabbing size */
*p = '\0';
/*
* replace sizes if they don't match!
*/
strcpy(sz, tmp);
if(strcmp(sz, (lblsz) ? lblsz : prettysz(l))){
strcpy(sz, (lblsz) ? lblsz : prettysz(l));
if(p-tmp > *off){ /* where to begin replacemnt */
j = (p-tmp) - *off;
sinserts((*lp)->text, *off, "", 0);
sinserts(&lprev->text[strlen(lprev->text)-j], j,
sz, strlen(sz));
*off = 0;
}
else{
j = (*off) - (p-tmp);
sinserts((*lp == NULL) ? &lprev->text[j]
: &(*lp)->text[j],
p-tmp , sz, strlen(sz));
*off += strlen(sz) - (p-tmp);
}
rv = 1;
}
p = tmp;
level = SWS; /* what's next... */
}
else if(c == '\0' || c == ','){
*p = '\0';
emlwrite("\007Attchmnt: Size field missing ')': \"%s\"", tmp);
rv = -1;
level = TG;
}
else
*p++ = c;
break;
case SWS: /* skip white space */
if(!isspace(c)){
if(c == ','){ /* no description */
level = TG; /* munch rest of garbage */
lbln = 0; /* reset flag */
}
else if(c != '\"' && c != '\0'){
emlwrite("\007Attchmnt: Malformed comment, quotes required", NULL);
rv = -1;
level = TG;
}
else
level = CMMNT;
}
break;
case CMMNT: /* slurp up comment */
if(c == '\"' || c == '\0'){ /* got comment */
*p = '\0'; /* cap it off */
p = tmp; /* reset p */
strcpy(cmnt,tmp); /* copy the comment */
if(c == '\0'){
emlwrite("\007Attchmnt: Closing quote required at end of comment", NULL);
rv = -1;
}
level = TG; /* prepare for next one */
lbln = 0; /* reset flag */
}
else
if(((*p++ = c) & 0x80) && !hibit++)
emlwrite(HIBIT_WARN, NULL);
break;
case TG: /* get comma or final EOL */
if(!isspace(c)){
if(c != ',' && c != '\0'){
if(rv != -1)
emlwrite("\007Attchmnt: Comma must separate attachments", NULL);
rv = -1;
}
}
break;
default: /* something's very wrong */
emlwrite("\007Attchmnt: Weirdness in ParseAttach", NULL);
return(-1); /* just give up */
}
if(c == '\0') /* we're done */
break;
(*off)++;
/*
* not in comment or label name? done.
*/
if(c == ',' && (level != CMMNT && !lbln))
break; /* put offset past ',' */
}
return(rv);
}
/*
* NewAttach - given a filename (assumed to accessible) and comment, creat
*/
PATMT *NewAttach(f, l, c)
char *f;
long l;
char *c;
{
PATMT *tp;
if((tp=(PATMT *)malloc(sizeof(PATMT))) == NULL){
emlwrite("No memory to add attachment", NULL);
return(NULL);
}
else
memset(tp, 0, sizeof(PATMT));
/* file and size malloc */
if((tp->filename = (char *)malloc(strlen(f)+1)) == NULL){
emlwrite("Can't malloc name for attachment", NULL);
free((char *) tp);
return(NULL);
}
strcpy(tp->filename, f);
if(l > -1){
tp->size = (char *)malloc(sizeof(char)*(strlen(prettysz(l))+1));
if(tp->size == NULL){
emlwrite("Can't malloc size for attachment", NULL);
free((char *) tp->filename);
free((char *) tp);
return(NULL);
}
else
strcpy(tp->size, prettysz(l));
}
/* description malloc */
if((tp->description = (char *)malloc(strlen(c)+1)) == NULL){
emlwrite("Can't malloc description for attachment", NULL);
free((char *) tp->size);
free((char *) tp->filename);
free((char *) tp);
return(NULL);
}
strcpy(tp->description, c);
/* callback to show user the mime type that will be used for attachment */
if(Pmaster->mimetype && (*Pmaster->mimetype)(f) > 0){
clearcursor();
mlerase();
(*Pmaster->showmsg)('x');
mpresf = 1;
}
return(tp);
}
/*
* AttachError - Sniff list of attachments, returning TRUE if there's
* any sign of trouble...
*/
int
AttachError()
{
PATMT *ap;
if(!Pmaster)
return(0);
ap = Pmaster->attachments;
while(ap){
if((ap->flags) & A_ERR)
return(1);
ap = ap->next;
}
return(FALSE);
}
void ZotAttach(p)
PATMT *p;
{
if(!p)
return;
if(p->description)
free((char *)p->description);
if(p->filename){
if(p->flags & A_TMP)
unlink(p->filename);
free((char *)p->filename);
}
if(p->size)
free((char *)p->size);
if(p->id)
free((char *)p->id);
p->next = NULL;
}
#endif /* ATTACHMENTS */
/*
* intag - return TRUE if i is in a column that makes up an
* attachment line number
*/
intag(s, i)
char *s;
int i;
{
char *p = s;
int n = 0;
while(*p != '\0' && (p-s) < 5){ /* is there a tag? it */
if(n && *p == '.') /* can't be more than 4 */
return(i <= p-s); /* chars long! */
if(*p < '0' || *p > '9')
break;
else
n = (n * 10) + (*p - '0');
p++;
}
return(FALSE);
}
/*
* prettysz - return pointer to string containing nice
*/
char *prettysz(l)
long l;
{
static char b[32];
if(l < 1000)
sprintf(b, "%d B", l); /* xxx B */
else if(l < 10000)
sprintf(b, "%1.1f KB", (float)l/1000); /* x.x KB */
else if(l < 1000000)
sprintf(b, "%d KB", l/1000); /* xxx KB */
else if(l < 10000000)
sprintf(b, "%1.1f MB", (float)l/1000000); /* x.x MB */
else
sprintf(b, "%d MB", l/1000000); /* xxx MB */
return(b);
}
/*
* sinserts - s insert into another string
*/
sinserts(ds, dl, ss, sl)
char *ds, *ss; /* dest. and source strings */
int dl, sl; /* their lengths */
{
char *dp, *edp; /* pointers into dest. */
int j; /* jump difference */
if(sl >= dl){ /* source bigger than dest. */
dp = ds + dl; /* shift dest. to make room */
if((edp = strchr(dp, '\0')) != NULL){
j = sl - dl;
for( ;edp >= dp; edp--)
edp[j] = *edp;
while(sl--)
*ds++ = *ss++;
}
else
emlwrite("\007No end of line???", NULL); /* can this happen? */
}
else{ /* dest is longer, shrink it */
j = dl - sl; /* difference in lengths */
while(sl--) /* copy ss onto ds */
*ds++ = *ss++;
if(strlen(ds) > j){ /* shuffle the rest left */
do
*ds = ds[j];
while(*ds++ != '\0');
}
else
*ds = '\0';
}
}